<template>
  <div class="v-crud-wrapper">
    <div class="v-crud-wrapper__header">
      <SearchBar
        v-if="vSearchBarConfig"
        ref="SearchBar"
        :config="vSearchBarConfig"
        @search="onSearch"
      />
      <div class="header-actions">
        <ElButton
          v-for="(item, index) in headerActions"
          :key="index"
          v-bind="item.options"
          @click="item.click"
        >
          {{ item.name }}
        </ElButton>
        <slot name="table-top" />
      </div>
    </div>
    <VTable
      v-if="vTableConfig"
      ref="VTable"
      class="v-crud-wrapper__body"
      :config="vTableConfig"
    />
    <CreateAndUpdatePopup
      v-if="vCreateAndUpdateConfig"
      ref="CreateAndUpdatePopup"
      :config="vCreateAndUpdateConfig"
      @success="() => $refs.VTable.refresh()"
    />
  </div>
</template>

<script>
import VTable from './components/Table/index'
import SearchBar from './components/SearchBar/index'
import CreateAndUpdatePopup from './components/CreateAndUpdatePopup/index'
import { controlSize } from '@lib/default'
import { configTableActionsColumn } from './tableActionsColumn'
import { getAndRemoveValue, isDef } from '../utils'
import { resolveButtonConfig } from './utils'
import { cloneDeep, isString, isArray, isFunction, isEmpty, clone } from 'lodash-es'

export default {
  components: {
    VTable,
    SearchBar,
    CreateAndUpdatePopup
  },

  provide() {
    return {
      // 统一设置后代表单控件的尺寸大小
      elFormItem: {
        elFormItemSize: controlSize
      },
      // 让各个子组件间通信方便，向后代组件提供一个事件控制中心
      eventsControler: {
        on: this.$on.bind(this),
        off: this.$off.bind(this),
        once: this.$once.bind(this),
        emit: this.$emit.bind(this)
      }
    }
  },

  props: {
    name: String,
    tableConfig: { required: true, type: Object },
    searchBarConfig: { type: Object },
    createAndUpdateConfig: { type: Object }
  },

  data() {
    return {
      vSearchBarConfig: null,
      vCreateAndUpdateConfig: null,
      vTableConfig: null,
      headerActions: [],
      selectedTableItems: []
    }
  },

  created() {
    this.resolveConfig()

    this.$on('selection-change', (items) => {
      this.selectedTableItems = items
    })
  },

  methods: {
    /**
     * 搜索
     */
    onSearch(query) {
      this.$refs['VTable'].search(query)
      this.$emit('search', clone(query))
    },
    /**
     * 刷新
     */
    refresh() {
      this.$refs['VTable'].refresh()
    },
    /**
     * 增删改
     */
    onChange() {
      this.$refs['VTable'].refresh()
      this.$emit('change')
    },
    /**
     * 获取查询参数
     */
    getQueryParams() {
      return clone(this.$refs.SearchBar.params)
    },
    /**
     * 获取被选的表格项
     */
    async getSelectedItems(opts = {}) {
      let items = this.selectedTableItems

      if (opts.filter) {
        items = items.filter(opts.filter)
      }

      if (isEmpty(items)) {
        if (opts.tooltip && this.$message) {
          this.$message.error(opts.tooltip)
        }
        return Promise.reject('')
      }

      if (opts.confirm) {
        const confirm = isString(opts.confirm) ? opts.confirm : '是否确定？'
        await this.$confirm(confirm, '提示')
      }

      return items
    },
    /**
     * 刷新字典
     */
    async refreshDicts(prop) {
      this.$refs.VTable.refreshDicts(prop)
      this.$refs.SearchBar && this.$refs.SearchBar.refreshDicts(prop)
      this.$refs.CreateAndUpdatePopup && this.$refs.CreateAndUpdatePopup.refreshDicts(prop)
    },
    /**
     * 处理配置
     */
    resolveConfig() {
      const tableConfig = cloneDeep(this.tableConfig)
      const createAndUpdateConfig = this.createAndUpdateConfig && cloneDeep(this.createAndUpdateConfig)

      // 处理表格配置
      tableConfig.name = tableConfig.name || this.name
      configTableActionsColumn(
        tableConfig,
        createAndUpdateConfig,
        this.resolveCreateOrUpdateButtonConfig(createAndUpdateConfig, true),
        this.getDeleteButtonConfig(getAndRemoveValue(tableConfig, 'delete'))
      )
      this.vTableConfig = tableConfig

      // 处理增和改的配置
      if (createAndUpdateConfig) {
        // "添加"按钮
        if (createAndUpdateConfig.create) {
          this.headerActions.push(
            this.resolveCreateOrUpdateButtonConfig(createAndUpdateConfig, false)
          )
        }

        createAndUpdateConfig.items = this.normalizeItems(createAndUpdateConfig.items)
        this.vCreateAndUpdateConfig = createAndUpdateConfig
      }

      // 处理搜索配置
      if (this.searchBarConfig) {
        const searchBarConfig = cloneDeep(this.searchBarConfig)
        searchBarConfig.items = this.normalizeItems(searchBarConfig.items)
        this.vSearchBarConfig = searchBarConfig
      }
    },
    /**
     * 规范化搜索栏和增改配置的items
     */
    normalizeItems(items) {
      const res = []

      let column
      for (let item of items) {
        if (isString(item)) {
          item = { column: item }
        }

        if (
          (column = getAndRemoveValue(item, 'column')) &&
          (column = this.vTableConfig.columns.find(c => c.prop === column))
        ) {
          item.label = column.label
          item.prop = item.prop || column.prop
          if (column.dicts) {
            if (isArray(column.dicts)) {
              item.dicts = column.dicts
            } else if (isFunction(column.dicts)) {
              // 让搜索栏、增改的表单、表格，使用同一个数据源
              const dicts = (column.dicts.dicts = column.dicts.dicts || [])
              item.dicts = () => dicts
              item.dicts.dicts = dicts
            }
          }
          if (!item.component && !item.render) {
            if (column.dicts) {
              item.component = 'select'
            } else {
              item.component = 'input'
            }
          }
        }

        res.push(item)
      }

      return res
    },
    /**
     * 处理添加/编辑按钮的配置
     */
    resolveCreateOrUpdateButtonConfig(
      createAndUpdateConfig,
      isUpdate
    ) {
      const button = createAndUpdateConfig && (
        isUpdate
          ? createAndUpdateConfig.update
          : createAndUpdateConfig.create
      )
      if (button) {
        const { handler, options = {}, name } = resolveButtonConfig(button)

        if (isUpdate) {
          createAndUpdateConfig.update = handler
        } else {
          createAndUpdateConfig.create = handler
        }

        options.type = options.type || 'primary'

        return {
          name: name || (isUpdate ? '编辑' : '新增'),
          click: data => {
            this.$refs.CreateAndUpdatePopup.show({
              isUpdate,
              data,
              onSuccess: this.onChange
            })
          },
          options
        }
      }
    },
    /**
     * 删除按钮的配置
     */
    getDeleteButtonConfig(button) {
      if (button) {
        const { handler, name = '删除', options, confirm = true } = resolveButtonConfig(button)

        let confirmMessage
        if (isDef(this.$confirm) && confirm) {
          confirmMessage = isString(confirm) ? confirm : '确认删除吗？'
        }

        return {
          name,
          click: async(data, { cancelLoading }) => {
            if (confirmMessage) {
              await this.$confirm(confirmMessage)
            }
            await handler(data)
            cancelLoading()
            this.onChange()
          },
          options: Object.assign({ type: 'danger' }, options)
        }
      }
    },
  }
}
</script>

<style lang="less">
.v-crud-wrapper {
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding: 15px 20px 20px 20px;
  box-sizing: border-box;

  &__header {
    margin-bottom: 5px;

    .v-crud--search-bar {
      margin-bottom: 5px;
    }

    .header-actions {
      margin-bottom: 5px;
      display: flex;
      flex-wrap: wrap;
    }
  }

  &__body {
    flex: 1;
    overflow: auto;

    .v-crud-table__actions {
      display: flex;
      flex-wrap: wrap;
      margin: -3px 0;

      .el-button {
        margin: 3px 5px 3px 0;

        [class*=el-icon-]+span {
          margin-left: 0;
          position: relative;
          left: 5px;
        }

        .el-icon-loading {
          position: absolute;
          left: 4px;
        }
      }
    }
  }
}
</style>
